package com.github.lzm320a99981e.component.dataautomation;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 数据分析模板
 */
@Slf4j
public class DataAutomationTemplate {
    /**
     * 数据抽取器
     */
    @Getter
    @Setter
    private List<Extractor> extractors;

    /**
     * 数据处理器
     */
    @Getter
    @Setter
    private List<Processor> processors;

    /**
     * 数据传输器
     */
    @Getter
    @Setter
    private List<Transfer> transfers;

    public DataAutomationTemplate() {
    }

    public DataAutomationTemplate(List<Extractor> extractors, List<Processor> processors, List<Transfer> transfers) {
        this.extractors = extractors;
        this.processors = processors;
        this.transfers = transfers;
    }

    /**
     * 请求参数与抽取器的映射
     */
    private Map<Class, Extractor> requestWithExtractorMap = Maps.newHashMap();
    /**
     * 抽取器类与抽取器的映射
     */
    private Map<Class, Extractor> classWithExtractorMap = Maps.newHashMap();

    /**
     * 处理器类与处理器的映射
     */
    private Map<Class, Processor> classWithProcessorMap = Maps.newHashMap();
    /**
     * 处理器与抽取器的映射
     */
    private Map<Class, List<Processor>> extractorWithProcessorsMap = Maps.newHashMap();
    /**
     * 传输器与处理器的映射
     */
    private Map<Class, List<Transfer>> processorWithTransfersMap = Maps.newHashMap();

    /**
     * 执行模板方法
     *
     * @param request
     */
    public void execute(Object request) {
        // ++++++++++++++++++++++++++++++ 抽取环节 ++++++++++++++++++++++++++++++
        // 获取当前线程上下文
        DataAutomationContext dataAutomationContext = DataAutomationContext.getCurrentContext();
        // 设置抽取请求参数
        dataAutomationContext.setExtractRequest(request);
        // 根据抽取请求参数找到对应的抽取器
        Extractor extractor = requestWithExtractorMap.get(request.getClass());
        // 获取抽取器的原始类型(因为使用retry框架，所以抽取器被创建为代理对象了，需要通过AopUtils.getTargetClass()接口获取到原始类型)
        Class<?> extractorClass = AopUtils.getTargetClass(extractor);
        // 抽取器抽取的接口信息
        dataAutomationContext.put("apiCode", ((AbstractExtractor) extractor).getApiCode());
        // 抽取器类型(方便失败后手动恢复)
        dataAutomationContext.setExtractorClass(extractorClass);

        // 执行抽取
        Object extractResponse = extractor.extract(request);
        // 如果抽取结果为空，则不进入到处理环节
        if (Objects.isNull(extractResponse)) {
            // 抽取结果为空可能存在两种请求：1.接口本身返回空 2.接口发生异常并且重试后仍然无效进入到恢复接口返回空，这种请求就需要进行终止处理，一般是将整个请求流程的上下文信息记录到日至系统，以方便后续恢复
            terminationHandle();
            return;
        }
        // 抽取结果
        dataAutomationContext.setExtractResponse(extractResponse);

        // ++++++++++++++++++++++++++++++ 处理环节 ++++++++++++++++++++++++++++++
        List<Processor> processors = extractorWithProcessorsMap.get(extractorClass);
        for (Processor processor : processors) {
            Class<?> processorClass = AopUtils.getTargetClass(processor);
            dataAutomationContext.setProcessorClass(processorClass);

            Object processResponse = processor.process(extractResponse);
            if (Objects.isNull(processResponse)) {
                terminationHandle();
                return;
            }
            dataAutomationContext.setProcessResponse(processResponse);

            // ++++++++++++++++++++++++++++++ 传输环节 ++++++++++++++++++++++++++++++
            List<Transfer> transfers = processorWithTransfersMap.get(processor.getClass());
            for (Transfer transfer : transfers) {
                transfer.transfer(processResponse);
                terminationHandle();
            }
        }

    }

    /**
     * 流程终止处理
     */
    public void terminationHandle() {
        DataAutomationContext dataAutomationContext = DataAutomationContext.getCurrentContext();
        if (dataAutomationContext.isTermination()) {
            log.warn("流程终止 :: 上下文信息 -> {}", JSON.toJSONString(dataAutomationContext, true));
        }
    }

    /**
     * 配置依赖关系
     */
    public void postConstruct() {
        for (Extractor extractor : extractors) {
            Class<?> extractorClass = AopUtils.getTargetClass(extractor);
            this.classWithExtractorMap.put(extractorClass, extractor);

            Class<?>[] declaredClasses = extractorClass.getDeclaredClasses();
            for (Class<?> declaredClass : declaredClasses) {
                if (Objects.equals("Request", declaredClass.getSimpleName())) {
                    this.requestWithExtractorMap.put(declaredClass, extractor);
                }
            }
        }

        for (Processor processor : processors) {
            Class<?> processorClass = AopUtils.getTargetClass(processor);
            this.classWithProcessorMap.put(processorClass, processor);

            Class<? extends Extractor>[] classes = processor.getClass().getAnnotation(Extractors.class).value();
            for (Class<? extends Extractor> aClass : classes) {
                if (!this.extractorWithProcessorsMap.containsKey(aClass)) {
                    this.extractorWithProcessorsMap.put(aClass, new ArrayList<>());
                }
                this.extractorWithProcessorsMap.get(aClass).add(processor);
            }
        }

        for (Transfer transfer : transfers) {
            Class<? extends Processor>[] classes = transfer.getClass().getAnnotation(Processors.class).value();
            for (Class<? extends Processor> aClass : classes) {
                if (!this.processorWithTransfersMap.containsKey(aClass)) {
                    this.processorWithTransfersMap.put(aClass, new ArrayList<>());
                }
                this.processorWithTransfersMap.get(aClass).add(transfer);
            }
        }
    }
}
